//James' Pass:		zS9AZ3gS8bR2
//Elliot's Pass:	Aa6zd6Bh7VG4
//Alex's Pass:		aw4zF7mc9Gv9

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;


public class GarbooMain extends JFrame implements ActionListener{

	
	
	private boolean WEIRD_FRAMELESSNESS=true;
	
	
	//General Engine variables
	Mode garbooMode = Mode.MENU;
	final int FRAMERATE = 60;
	final int WIDTH = 1280, HEIGHT = 800 + 80;
	Timer frameTimer = new Timer((int)(1.0/FRAMERATE* 1000), this);
	int xoff, yoff;  //Offsets for dealing with the window borders for drawing
	Font gFont_big, gFont_small;
	BufferedImage menuBuffer, ingameBuffer, helpBuffer, pauseBuffer;


	//Menu vars
	MenuListeners mListener;
	Image menu_img, selector_img;
	final int menu_start_x = 150;
	final int menu_start_y = 425;
	final int menu_item_dy = 42;
	int menuSelection = 0;



	//Help vars
	HelpListeners hListener;
	Image wtf, wtf2;
	int helpScreenNumber = 0;


	//Game vars
	InGameListeners igListener;
	PauseListeners pListener;
	PauseMode pauseMode = PauseMode.CLICK_TO_BEGIN;
	Image player_img,mp_vert,mp_horiz; //Moving platform images

	//Game engine variables
	final String LEVELDIR = "Levels/";
	final String FIRSTLEVEL = "11";
	final int PIXELS_PER_METER = 15;
	final int FG = 40; //meters


	//Level-specific variables
	Level currentLevel;
	ArrayList<Draw> draws;
	Player player;
	ArrayList<Integer> tilesToCheck;
	Rectangle exitRect;

	public GarbooMain(){
		//Load images
		try {
			menu_img = ImageIO.read(new File("menuimg.png"));
			selector_img= ImageIO.read(new File("selectorimg.png"));

			wtf = ImageIO.read(new File("wtf.png"));
			wtf2= ImageIO.read(new File("wtf2.png"));

			mp_vert = ImageIO.read(new File(LEVELDIR + "moving_v.png"));
			mp_horiz= ImageIO.read(new File(LEVELDIR + "moving_h.png"));

			player_img = ImageIO.read(new File(LEVELDIR + "player.png"));


		} catch (IOException e) {
			System.err.println("Could not read some images....");
			e.printStackTrace();
			System.exit(0);
		}

		//Load the Garboo font

		try {		
			Font gFont;
			gFont = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream(new File("garboo.ttf")));
			gFont_big = gFont.deriveFont(60f);
			gFont_small = gFont.deriveFont(20f);
		} catch (Exception e) {
			System.err.println("Could not load \"garboo.ttf\".");
			e.printStackTrace();
			System.exit(0);  //must exit since the fonts and the derivatives have NOT been defined properly...
		}


		//Initialize all listeners
		igListener= new InGameListeners();
		mListener = new MenuListeners();
		hListener = new HelpListeners();
		pListener = new PauseListeners();

		//Start out by setting the menu listener to be the active one

		setListeners(mListener);


		//Initialize back-buffers
		ingameBuffer = new BufferedImage(WIDTH,HEIGHT, BufferedImage.TYPE_INT_RGB);
		menuBuffer   = new BufferedImage(WIDTH,HEIGHT, BufferedImage.TYPE_INT_RGB);
		helpBuffer 	 = new BufferedImage(WIDTH,HEIGHT, BufferedImage.TYPE_INT_RGB);
		pauseBuffer  = new BufferedImage(WIDTH,HEIGHT, BufferedImage.TYPE_INT_RGB);


		//Initialize the window

		paintMenuBuffer();

		setResizable(false);
		setAlwaysOnTop(true);
		
		setUndecorated(WEIRD_FRAMELESSNESS);
		setVisible(true);

		GraphicsConfiguration gc = this.getGraphicsConfiguration();
		Rectangle gc_r = gc.getBounds();
		this.setLocation(gc_r.width/2 - WIDTH/2, gc_r.height/2 - HEIGHT/2);
		
		xoff = getInsets().left;
		yoff = getInsets().top;
		System.out.println("Offsets:"+ getInsets());
		System.out.println("xoff, yoff: "+xoff+" , "+yoff);

		setSize(     //Set the size to adjust for window borders
				WIDTH+      getInsets().left + getInsets().right,
				HEIGHT + getInsets().top + getInsets().bottom);

		setDefaultCloseOperation(EXIT_ON_CLOSE);

		//Start the frame-updater thread
		frameTimer.start();

	}


	public void setListeners(GenericListener o) {

		for(MouseListener l:getMouseListeners()) removeMouseListener(l);
		for(KeyListener l:getKeyListeners()) removeKeyListener(l);
		for(MouseMotionListener l:getMouseMotionListeners()) removeMouseMotionListener(l);

		addMouseListener(o);
		addMouseMotionListener(o);
		addKeyListener(o);



	}

	public void actionPerformed(ActionEvent e){
		//Frame-timer action-performed: ONLY USE IT TO RUN TASKS WHICH SHOULD BE DONE EACH FRAME, REDRAW THE BUFFER, AND REPAINT

		switch(garbooMode){
		case INGAME:
			aP_game(e);
			break;
		case MENU:
			aP_menu(e);
			break;
		case HELP:
			aP_help(e);
			break;
		case PAUSE:
			aP_pause(e);
			break;
		}
	}


	/**
	 * **********************
	 * MAIN MENU ACTION PERFORMED AND BUFFERPAINT/REPAINT
	 * **********************
	 */

	public void aP_menu(ActionEvent e){
		paintMenuBuffer();
		repaint();
	}
	public void paintMenuBuffer(){
		Graphics2D g2 = (Graphics2D)menuBuffer.getGraphics();
		g2.drawImage(menu_img, 0, 0, null);


		//Draw selector image level with the menu choices
		g2.drawImage( 
				selector_img,
				menu_start_x ,
				menu_start_y + menuSelection*menu_item_dy - (int)Math.round(selector_img.getHeight(null)/2.0),
				null );

	}


	/**
	 * **********************
	 * HELP MENU ACTION PERFORMED AND BUFFERPAINT/REPAINT
	 * **********************
	 */

	public void aP_help(ActionEvent e){
		paintHelpBuffer();
		repaint();
	}
	public void paintHelpBuffer(){
		Graphics2D g2 = (Graphics2D)helpBuffer.getGraphics();

		if( helpScreenNumber == 0){
			g2.drawImage( wtf, 0,0,null);
		}
		else if(helpScreenNumber == 1){
			g2.drawImage( wtf2, 0,0,null);
		}
	}


	/**
	 * **********************
	 * PAUSE MENU ACTION PERFORMED AND BUFFERPAINT/REPAINT
	 * **********************
	 */

	public void aP_pause(ActionEvent e){
		paintPauseBuffer();
		repaint();
	}
	public void paintPauseBuffer(){
		Graphics2D g2 = (Graphics2D)pauseBuffer.getGraphics();

		paintGameBuffer();
		g2.drawImage( ingameBuffer, 0, 0, null);

		//Draw the opaque gray box
		g2.setColor(new Color( .2f, .2f, .2f, .6f));
		g2.fillRect(0,0,WIDTH, HEIGHT-80);

		//Draw the text that goes on each screen

		g2.setColor(Color.WHITE);

		switch(pauseMode){
		case USER_PAUSE:

			g2.setFont(gFont_big);
			g2.drawString("GAME PAUSED", 415, 360);

			g2.setFont(gFont_small);
			g2.drawString(" press >>esc<< to quit to main menu", 432, 430);
			g2.drawString(" press >> P << to resume game", 465, 460);

			g2.drawString("Be sure to make note of the level code, so you can return here", 243, 550);
			g2.drawString("without having to play through all the previous levels again", 253,580 );

			break;

		case CLICK_TO_BEGIN:
			g2.setFont(gFont_big);
			g2.drawString("CLICK TO BEGIN", 395, 360);

			g2.setFont(gFont_small);
			g2.drawString(" press >>esc<< to quit to main menu", 432, 430);

			g2.drawString("Be sure to make note of the level code, so you can return here", 243, 550);
			g2.drawString("without having to play through all the previous levels again", 253,580 );


			break;
		case CLICK_TO_RESPAWN:

			g2.setFont(gFont_big);
			g2.drawString("CLICK TO RESPAWN", 327, 360);

			g2.setFont(gFont_small);
			g2.drawString(" press >>esc<< to quit to main menu", 432, 430);

			g2.drawString("Be sure to make note of the level code, so you can return here", 243, 550);
			g2.drawString("without having to play through all the previous levels again", 253,580 );

			break;
		}

	}


	/**
	 * **********************
	 * IN-GAME ACTION PERFORMED AND BUFFERPAINT/REPAINT
	 * **********************
	 */

	public void aP_game(ActionEvent e) {
		long s_time = System.currentTimeMillis();

		//BM: Apply gravitation -> displacement to the player
		player.vel.y += (FG*(1.0/FRAMERATE)); //Apply gravity force, assuming unit mass.


		//	Integrate the velocity to find the new position
		//  also, updates player rectangle
		player.moveCenterTo( m2px( px2m(player.ctr.x) + player.vel.x * (1.0/FRAMERATE)), m2px(px2m(player.ctr.y) + player.vel.y * (1.0/FRAMERATE)));

		
		
		//BM: Update all moving platform positions and laserwall's on/off-ness

		for(MovingPlatform mp: currentLevel.movingPlatforms){
			mp.update();
		}
		for(LaserWall lw: currentLevel.laserWalls){
			lw.update();
		}


		//BM: Check for collisions with any tiles in the vicinity
		tilesToCheck = currentLevel.adjPlace(player.ctr.x, player.ctr.y);
		for(Integer i: tilesToCheck){
			if( currentLevel.tileCollisionRectangles[i].intersects(player.getRect()) ){
				killPlayer();
				break;
			}
		}


		if( //Check for player going out of bounds
				! (	(0<=player.ctr.x) && (player.ctr.x<=WIDTH) ) ||  
				! (	(0<=player.ctr.y) && (player.ctr.y<= HEIGHT-80) ) //height-80 b/c the height includes the bottombar
		){
			killPlayer();
		}


		//TODO: check for collisions with laserwalls
		for(LaserWall lw: currentLevel.laserWalls){
			if( lw.isOn() && player.getRect().intersects(lw.getRect())){
				killPlayer();
				break;
			}
		}

		//BM: check for collisions with moving platforms
		for(MovingPlatform mp: currentLevel.movingPlatforms){
			if(player.getRect().intersects(mp.getRect())){
				killPlayer();
				break;
			}
		}


		//BM: Check for reaching the exit! :) 
		if( exitRect.intersects(player.getRect())){
			loadNextLevel();
		}


		//BM: Check for collisions with draws
		double[]cres; //collision results
		int indexToDelete=-1;
		int ndx = 0;
		for(Draw draw: draws){
			cres = PhysicsMethods.collisionStuff(player.getRect(),
					draw.start(), draw.end(), player.vel);

			if(cres[4]==1){ // A collision event took place:
				indexToDelete = ndx;
				//Displace player
				player.moveCenterTo(player.ctr.x+ cres[0], player.ctr.y + cres[1]);

				player.vel.x = px2m(cres[2]);
				player.vel.y = px2m(cres[3]);
				//	draws.remove(draws.size()-1);
			}			
			ndx++;
		}
		if(indexToDelete>-1){
			draws.remove(indexToDelete);
		}

		//BM: Paint all the stuff to the screen
		paintGameBuffer();
		repaint();
		System.out.println(( System.currentTimeMillis()-s_time)+ " ms per frame.");

	}	
	public void paintGameBuffer(){
		Graphics2D g2 = (Graphics2D)ingameBuffer.getGraphics();
		
		//BM: Paint bg image (custom drawn for each level) and black bottom bar
		g2.drawImage(currentLevel.levelBackground, 0, 0, null);

		//BM: Draw bottom bar and level text stuff:
		g2.setColor(Color.black);
		g2.fillRect(0, 800 , WIDTH, 80);
		g2.setColor(Color.white);
		g2.setFont(gFont_big.deriveFont(30f));
		g2.drawString( "L"+currentLevel.numeric_num+":  _<"+currentLevel.lnum+">", 30, 840);


		//BM: draw temporary tiles
		for( Rectangle r: currentLevel.tileCollisionRectangles){
			g2.setColor(Color.black);
			g2.fill(r);
			g2.setColor(Color.red);
			g2.draw(r);
		}


		//BM: draw temporary end and start points
		g2.setColor(Color.blue);
		g2.fillRect((int)currentLevel.playerstart.x-5, (int)currentLevel.playerstart.y-5 , 10, 10);
		g2.setColor(Color.green);
		g2.fill(exitRect);


		//TODO: Draw temporary moving platforms
		for( MovingPlatform mp: currentLevel.movingPlatforms){
			g2.drawImage( (mp.getOrient() == 0)?mp_horiz:mp_vert, mp.getDrawX(), mp.getDrawY(),null);
		}

		//BM: Draw laser walls

		for( LaserWall lw: currentLevel.laserWalls){
			if( lw.isOn()){
				g2.setColor( Color.red);
			}
			else{
				g2.setColor( Color.gray);
			}
			g2.fill(lw.getRect());

		}


		//BM: Draw player
		g2.drawImage( player_img, player.getRect().x, player.getRect().y, null);

		//BM: Draw velocity vector for the player
		g2.setColor(Color.green);
		g2.drawLine( (int)Math.round(player.ctr.x), (int)Math.round(player.ctr.y), 
				(int)Math.round(player.ctr.x + player.vel.x),
				(int)Math.round(		player.ctr.y + player.vel.y)
		);


		//BM: draw 
		for(Draw d: draws){
			d.drawSelf(g2);
		}

	}

	/******/

	/** This method will prepare the level specified by
	 *  loading the definition into currentLevel, clearing
	 *  and allocating an array for Draw objects, and 
	 *  spawning a Player object at the PlayerStart position
	 *  specified in the level definiton.
	 * @param lvl The level to be loaded. Do not prefix
	 *  with level's path, just provide the name.
	 */
	public void prepareLevel(String lvl) {

		System.out.println("Prepping:"+ LEVELDIR + lvl);

		//Load level, initialize player and an array for keeping track of draws
		currentLevel = new Level(LEVELDIR + lvl, FRAMERATE); //test level
		exitRect = new Rectangle(
				(int)currentLevel.playerexit.x - 30,
				(int)currentLevel.playerexit.y - 30,
				60,60);

		draws = new ArrayList<Draw>(20);  //init with 20 just to be safe
		//Note: the player-class constructor uses clones of the passed-in Point2D.Doubles instead of the references passed in
		player = new Player(currentLevel.playerstart,20,32,currentLevel.playervel);

	}
	public void quickReset() {

		//Reset the player to their old position.
		player = new Player(currentLevel.playerstart,20,32,currentLevel.playervel);
		draws.clear(); //reset all the draws

		for(MovingPlatform mp: currentLevel.movingPlatforms)
			mp.reset();
		for(LaserWall lw: currentLevel.laserWalls)
			lw.reset();

		System.out.println("Reset the MPs...");

		//For when it's actually implemented...
		//		for(LaserWall lw: currentLevel.laserWalls)
		//			lw.reset();

	}
	public void killPlayer(){
		//		quickReset();
		System.out.println("killed player");
		pauseMode = PauseMode.CLICK_TO_RESPAWN;
		garbooMode = Mode.PAUSE;
		paintPauseBuffer();
		setListeners( pListener);
	}


	public void loadNextLevel() {

		//If there is a next level, load it, otherwise... TBD
		if(currentLevel.nextLevel!=null){
			prepareLevel( currentLevel.nextLevel);

			pauseMode = PauseMode.CLICK_TO_BEGIN;
			garbooMode = Mode.PAUSE;
			paintPauseBuffer();
			setListeners(pListener);
		}else{
			JOptionPane.showMessageDialog(null, "End of user testing. Thank you.");

			garbooMode = Mode.MENU;
			setListeners(mListener);
		}
	}

	/******/

	public double m2px(double m){
		return m*PIXELS_PER_METER;
	}
	public double px2m(double px){
		return px/PIXELS_PER_METER;
	}

	/******/

	public void paint(Graphics g){

		switch(garbooMode){
		case INGAME:
			g.drawImage(ingameBuffer,	getInsets().left, getInsets().top,null);

			break;

		case MENU:
			//			System.out.println("Drawing menu");
			g.drawImage( menuBuffer, getInsets().left, getInsets().top, null);
			break;

		case HELP:

			g.drawImage (helpBuffer, getInsets().left, getInsets().top, null);
			break;

		case PAUSE:
			//			System.out.println("Paint! [Pause]");
			g.drawImage ( pauseBuffer , getInsets().left, getInsets().top, null);
		}



	}
	public void update(Graphics g){	paint(g); }

	/******/

	public static void main(String[]args){new GarbooMain(); }

	/******/

	public class CodeFinder implements Runnable{
		private boolean codeFound;
		private boolean doneSearching;
		private String level;
		private String code;

		public CodeFinder(String code){
			codeFound = false;
			doneSearching = false;
			this.code = code;
		}
		public void run() {

			for(int i = 1; i<5;i++){ //1-4
				for(int j = 1;j<=5;j++){ // 1-5
					System.out.println("Looking in: "+LEVELDIR+i+""+j);
					ArrayList<String> fileText = new ArrayList<String>();
					try {
						//Load in level data into an arraylist for tag-searching
						Scanner fin = new Scanner(new FileReader(LEVELDIR + i+""+j));
						while(fin.hasNextLine()){
							fileText.add(fin.nextLine());

							//Remove comments and blank lines from file text
							if(fileText.get(fileText.size()-1).equals("") ||
									fileText.get(fileText.size()-1).startsWith("//"))

								fileText.remove(fileText.size()-1);
						}
					} catch (FileNotFoundException e) {
						System.err.println("Unable to read level definition!");
						e.printStackTrace();			
					}
					//Look for a LNUM tag...
					String lnum = null;

					for(int k = 0; k < fileText.size(); k++	){
						String line = fileText.get(k).trim();	
						switch(line.charAt(0)){
						case 'L':
							if(line.substring(0, line.indexOf(" ")).trim().equals("LNUM")){
								//								System.out.println("FOUND LEVEL NAME TAG:"+line);
								lnum = line.substring(line.indexOf(" ")).trim();
							}else{
								//								System.out.println("L TAG WAS NOT FOR LEVEL NAME:"+line);
							}
							if(lnum!=null && lnum.equals(code)){ //This is our match!
								codeFound = true;
								doneSearching = true;
								level = i+""+j;
								System.out.println("Found the match: "+lnum+" matches the given code, "+code);
								return;
							}
							break;
						}
					}
					System.out.println("Finished looking at :"+LEVELDIR + i + ""+j);
				}
			}
			doneSearching = true;

		}
		public String getFoundLevel(){
			return level;
		}
		public boolean isDoneSearching(){
			return doneSearching;
		}
		public boolean isCodeFound(){
			return codeFound;
		}

	}

	public class PauseListeners extends GenericListener{
		public void keyPressed(KeyEvent e){
			System.out.println("KeyPressed! [PauseListener]");

			if(pauseMode == PauseMode.USER_PAUSE){
				if(e.getKeyCode() == KeyEvent.VK_P){ //unpause the game

					garbooMode = Mode.INGAME;
					setListeners(igListener);

				}
			}

			//regardless, escape is always quit so, do so
			if(e.getKeyCode() == KeyEvent.VK_ESCAPE){

				garbooMode = Mode.MENU;
				setListeners(mListener);

				//TODO: force a respawn? actually, not needed, because
				// 'start a new game' will autoforce a respawn
			}
		}
		public void mousePressed(MouseEvent e){
			if(pauseMode == PauseMode.CLICK_TO_BEGIN || pauseMode == PauseMode.CLICK_TO_RESPAWN){

				if(pauseMode == PauseMode.CLICK_TO_RESPAWN){ //we need to clear draws and replace player
					//at PS if we just died.
					//quickReset();
					//					ingameBuffer.getGraphics().clearRect(0,0,1000,1000);
				} // ??? What was the above 2 lines for??

				quickReset(); //fuckit, why not clear & reset ANYWAYS? not like it hurts
				garbooMode = Mode.INGAME;
				setListeners(igListener);

			}

		}

	}

	public class InGameListeners extends GenericListener{
		boolean btn1 = false; //flag for determining if its a left-click drag

		public void mousePressed(MouseEvent e) {
			System.out.println("mods"+e.getModifiers());
			if(e.getButton() == MouseEvent.BUTTON1){
				btn1 = true;
				System.out.println("NEW DRAW MADE");
				Point p = e.getPoint(); //Correct the offsets due to borders...
				p.x-=xoff; p.y-=yoff;
				draws.add(new Draw( p, p));
			}else if(e.getButton() == MouseEvent.BUTTON3){

				if(draws.size()>0){  // ...only if we have a draw left to erase.
					draws.remove( draws.size() - 1);
				}

			}
		}
		public void mouseDragged(MouseEvent e) {

			if(btn1 ){
				Point p = e.getPoint();
				p.x-=xoff; p.y-=yoff;
				if(draws.size() !=0 ){
					draws.get(draws.size()-1).moveEndpointTo(p);
				}
			} //we dont care if mouse3 drags aroundq
		}
		public void mouseReleased(MouseEvent e){
			btn1 = false;
		}
		public void keyPressed(KeyEvent e){

			if(e.getKeyCode() == KeyEvent.VK_P || e.getKeyCode() == KeyEvent.VK_ESCAPE){ // I find myself instinctively using Esc to pause...

				pauseMode = PauseMode.USER_PAUSE;
				garbooMode = Mode.PAUSE;
				paintPauseBuffer();
				setListeners(pListener);

			}

			if(e.getKeyCode() == KeyEvent.VK_K){
				quickReset(); //i think it should quickreset b/c something has
				//obv. gone out of whack if you need to use this
				killPlayer();


			}


		}
	}

	public class MenuListeners extends GenericListener{
		public void keyPressed(KeyEvent e) {

			//			System.out.println("src: "+ e.getSource());
			System.out.println("id: "+ e.getID());
			System.out.println("modifiers:"+e.getModifiers());
			System.out.println("keycode:"+e.getKeyCode());
			System.out.println("keycode for x is:"+KeyEvent.VK_X);




			System.out.println("Key Pressed! [Menu]");
			if(e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_RIGHT){


				menuSelection = (menuSelection+1)%4;

			}else if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_LEFT){
				if( menuSelection == 0)
					menuSelection = 3;
				else
					menuSelection = (menuSelection-1)%4;
			}

			else if( e.getKeyCode() == KeyEvent.VK_ENTER){

				if( menuSelection == 0){

					prepareLevel(FIRSTLEVEL);

					//Set the mode to be in-game and set the listeners to be in-game listeners
					setListeners( igListener );
					garbooMode = Mode.INGAME;

					//TODO: This will launch us into game mode... make it go into paused mode (click to start!)

					pauseMode = PauseMode.CLICK_TO_BEGIN;
					garbooMode = Mode.PAUSE;
					paintPauseBuffer();
					setListeners( pListener);


				}else if(menuSelection == 1){
					//Pop up a box to read which code we're using.

					String enteredCode = JOptionPane.showInputDialog("What's this code you speak of?");
					if( enteredCode!=null){
						CodeFinder codeFinder = new CodeFinder(enteredCode);
						codeFinder.run();

						while(!codeFinder.isDoneSearching()); //wait for codefinder to finish searching

						if(codeFinder.isCodeFound()){
							JOptionPane.showMessageDialog(null, "Level found: Level "+codeFinder.getFoundLevel()+"!");

							prepareLevel(codeFinder.getFoundLevel());

							//Set the mode to be in-game and set the listeners to be in-game listeners
							setListeners( igListener );
							garbooMode = Mode.INGAME;

							pauseMode = PauseMode.CLICK_TO_BEGIN;
							garbooMode = Mode.PAUSE;
							paintPauseBuffer();
							setListeners( pListener);


						}else{
							JOptionPane.showMessageDialog(null,"Make sure you have the level code right. No levels with the code you specified were found.");
						}
					}

				}else if(menuSelection == 2){ //wtf screens

					setListeners(hListener);
					garbooMode = Mode.HELP;
					helpScreenNumber = 0; //make sure we start at the first help screen

				}else if(menuSelection == 3){ //exit!
					System.exit(0);
				}



			}
		}
	}

	public class HelpListeners extends GenericListener{
		public void keyPressed(KeyEvent e) {
			System.out.println("Key Down! [Help]");
			if( e.getKeyCode() == KeyEvent.VK_RIGHT){
				System.out.println("RIGHT KEY");
				if( helpScreenNumber == 0){
					helpScreenNumber = 1;
				}
				System.out.println("helpScreenNumber is now: "+helpScreenNumber);
			}else if(e.getKeyCode() == KeyEvent.VK_LEFT){
				System.out.println("LEFT KEY");
				if(helpScreenNumber == 1){
					helpScreenNumber = 0;
				}
			}else if(e.getKeyCode() == KeyEvent.VK_ENTER){
				setListeners(mListener);
				garbooMode = Mode.MENU;
				menuSelection = 0; //reset the menu to select the first item :)

			}

			else if( e.getKeyCode() == KeyEvent.VK_ENTER){
				//FIXME: start the game
			}
		}
	}

	public class GenericListener  implements KeyListener, MouseListener, MouseMotionListener{

		public void mouseDragged(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void mouseMoved(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void mouseClicked(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void mouseEntered(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void mouseExited(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void mousePressed(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void mouseReleased(MouseEvent e) {
			// TODO Auto-generated method stub

		}
		public void keyPressed(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}
		public void keyReleased(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}
		public void keyTyped(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}

	}


}
